import React, { useState, useEffect, useRef } from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  ActivityIndicator,
  StyleSheet,
  Platform,
  PanResponder,
  GestureResponderEvent,
  PanResponderGestureState,
  Vibration,
} from 'react-native';
import Sound from 'react-native-sound';
import { theme } from '../../styles/theme';

// Enable playback in silence mode (iOS only)
Sound.setCategory('Playback', true);

export interface AudioPlayerInterface {
  load: (url: string) => Promise<void>;
  play: () => void;
  pause: () => void;
  stop: () => void;
  seek: (seconds: number) => void;
  getDuration: () => number;
  getCurrentTime: () => number;
  setPlaybackRate: (rate: number) => void;
  isPlaying: () => boolean;
  release: () => void;
}

export class NativeAudioPlayer implements AudioPlayerInterface {
  private sound: Sound | null = null;
  private timeInterval: NodeJS.Timeout | null = null;
  private onTimeUpdate: ((time: number) => void) | null = null;
  private onEnd: (() => void) | null = null;
  private onError: ((error: Error) => void) | null = null;
  private url: string = '';

  constructor() {
    // Set to default values
  }

  public setOnTimeUpdate(callback: (time: number) => void): void {
    this.onTimeUpdate = callback;
  }

  public setOnEnd(callback: () => void): void {
    this.onEnd = callback;
  }

  public setOnError(callback: (error: Error) => void): void {
    this.onError = callback;
  }

  public async load(url: string): Promise<void> {
    // Stop any previous sound
    this.stop();

    this.url = url;

    return new Promise((resolve, reject) => {
      // Create a new sound instance
      this.sound = new Sound(url, undefined, (error) => {
        if (error) {
          if (this.onError) {
            this.onError(new Error(`Failed to load sound: ${error.message}`));
          }
          reject(error);
          return;
        }

        resolve();
      });

      // Set up callbacks
      if (this.sound) {
        this.sound.setNumberOfLoops(0); // Don't loop
      }
    });
  }

  public play(): void {
    if (!this.sound) return;

    // Start playing the sound
    this.sound.play((success) => {
      if (success) {
        if (this.onEnd) {
          this.onEnd();
        }
      } else {
        if (this.onError) {
          this.onError(new Error('Playback failed due to audio decoding errors'));
        }
      }
    });

    // Start the timer to update time
    this.startTimeUpdateInterval();
  }

  public pause(): void {
    if (!this.sound) return;

    this.sound.pause();
    this.stopTimeUpdateInterval();
  }

  public stop(): void {
    if (!this.sound) return;

    this.sound.stop();
    this.stopTimeUpdateInterval();

    // Clean up the sound
    this.release();
  }

  public seek(seconds: number): void {
    if (!this.sound) return;

    this.sound.setCurrentTime(seconds);

    if (this.onTimeUpdate) {
      this.onTimeUpdate(seconds);
    }
  }

  public getDuration(): number {
    if (!this.sound) return 0;
    return this.sound.getDuration();
  }

  public getCurrentTime(): number {
    if (!this.sound) return 0;

    let time = 0;
    this.sound.getCurrentTime((seconds) => {
      time = seconds;
    });

    return time;
  }

  public setPlaybackRate(rate: number): void {
    if (!this.sound) return;

    if (Platform.OS === 'ios' || Platform.OS === 'android') {
      this.sound.setSpeed(rate);
    }
  }

  public isPlaying(): boolean {
    if (!this.sound) return false;
    return this.sound.isPlaying();
  }

  public release(): void {
    this.stopTimeUpdateInterval();

    if (this.sound) {
      this.sound.release();
      this.sound = null;
    }
  }

  private startTimeUpdateInterval(): void {
    this.stopTimeUpdateInterval(); // Clear any existing interval

    this.timeInterval = setInterval(() => {
      if (this.sound && this.onTimeUpdate) {
        this.sound.getCurrentTime((seconds) => {
          if (this.onTimeUpdate) {
            this.onTimeUpdate(seconds);
          }
        });
      }
    }, 250); // Update every 250ms for better performance
  }

  private stopTimeUpdateInterval(): void {
    if (this.timeInterval) {
      clearInterval(this.timeInterval);
      this.timeInterval = null;
    }
  }
}

interface AudioPlayerProps {
  url: string;
  title?: string;
  autoPlay?: boolean;
  onEnded?: () => void;
  style?: any;
}

const AudioPlayer: React.FC<AudioPlayerProps> = ({
  url,
  title,
  autoPlay = false,
  onEnded,
  style,
}) => {
  const [player] = useState<AudioPlayerInterface>(new NativeAudioPlayer());
  const [isLoading, setIsLoading] = useState(true);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [error, setError] = useState<Error | null>(null);
  const [isSeeking, setIsSeeking] = useState(false);
  const [seekValue, setSeekValue] = useState(0);
  const [playbackRate, setPlaybackRate] = useState(1.0);
  const progressBarWidth = useRef(0);

  // Create pan responder for the progress bar
  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        setIsSeeking(true);
        // Add haptic feedback on touch
        if (Platform.OS !== 'web') {
          Vibration.vibrate(10);
        }
      },
      onPanResponderMove: (
        _: GestureResponderEvent,
        gestureState: PanResponderGestureState
      ) => {
        const position = Math.max(0, Math.min(gestureState.moveX, progressBarWidth.current));
        const percentage = position / progressBarWidth.current;
        const seekTime = percentage * duration;
        setSeekValue(seekTime);
      },
      onPanResponderRelease: () => {
        player.seek(seekValue);
        setCurrentTime(seekValue);
        setIsSeeking(false);
      },
    })
  ).current;

  useEffect(() => {
    let mounted = true;

    const loadAudio = async () => {
      try {
        setIsLoading(true);
        setError(null);
        await player.load(url);

        if (mounted) {
          const audioDuration = player.getDuration();
          setDuration(audioDuration);
          setIsLoading(false);

          if (autoPlay) {
            handlePlay();
          }
        }
      } catch (err) {
        if (mounted) {
          setError(err instanceof Error ? err : new Error('Failed to load audio'));
          setIsLoading(false);
        }
      }
    };

    // Set up event callbacks
    if (player instanceof NativeAudioPlayer) {
      player.setOnTimeUpdate((time) => {
        if (!isSeeking && mounted) {
          setCurrentTime(time);
        }
      });

      player.setOnEnd(() => {
        if (mounted) {
          setIsPlaying(false);
          setCurrentTime(duration);

          if (onEnded) {
            onEnded();
          }
        }
      });

      player.setOnError((err) => {
        if (mounted) {
          setError(err);
          setIsPlaying(false);
        }
      });
    }

    loadAudio();

    // Cleanup function
    return () => {
      mounted = false;
      player.release();
    };
  }, [url, player, autoPlay, onEnded]);

  const handlePlay = () => {
    player.play();
    setIsPlaying(true);
  };

  const handlePause = () => {
    player.pause();
    setIsPlaying(false);
  };

  const handleSeek = (value: number) => {
    player.seek(value);
    setCurrentTime(value);
  };

  const handleProgressBarLayout = (event: any) => {
    progressBarWidth.current = event.nativeEvent.layout.width;
  };

  const handleProgressBarTouch = (event: GestureResponderEvent) => {
    if (progressBarWidth.current > 0) {
      const touchX = event.nativeEvent.locationX;
      const percentage = Math.max(0, Math.min(touchX, progressBarWidth.current)) / progressBarWidth.current;
      const seekTime = percentage * duration;
      handleSeek(seekTime);

      // Add haptic feedback on touch
      if (Platform.OS !== 'web') {
        Vibration.vibrate(10);
      }
    }
  };

  const changePlaybackRate = () => {
    // Cycle through rates: 1.0 -> 1.5 -> 2.0 -> 0.75 -> 1.0
    const rates = [1.0, 1.5, 2.0, 0.75];
    const nextRateIndex = (rates.indexOf(playbackRate) + 1) % rates.length;
    const newRate = rates[nextRateIndex];

    player.setPlaybackRate(newRate);
    setPlaybackRate(newRate);

    // Add haptic feedback on rate change
    if (Platform.OS !== 'web') {
      Vibration.vibrate(15);
    }
  };

  const formatTime = (timeInSeconds: number): string => {
    const minutes = Math.floor(timeInSeconds / 60);
    const seconds = Math.floor(timeInSeconds % 60);
    return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
  };

  const progressPercentage = duration > 0 ? (currentTime / duration) * 100 : 0;
  const seekPercentage = duration > 0 ? (seekValue / duration) * 100 : 0;

  return (
    <View style={[styles.container, style]}>
      <View style={styles.playerContainer}>
        {/* 标题和时间 */}
        <View style={styles.header}>
          <Text style={styles.title} numberOfLines={1} ellipsizeMode="tail">
            {title || '音频文件'}
          </Text>
          <TouchableOpacity
            style={styles.rateButton}
            onPress={changePlaybackRate}
            disabled={!duration || !!error}
          >
            <Text style={styles.rateButtonText}>{playbackRate}x</Text>
          </TouchableOpacity>
          <Text style={styles.timeText}>
            {isSeeking ? formatTime(seekValue) : formatTime(currentTime)} / {formatTime(duration)}
          </Text>
        </View>

        {/* 进度条 */}
        <View style={styles.progressContainer} onLayout={handleProgressBarLayout}>
          <TouchableOpacity
            activeOpacity={1}
            style={styles.progressBackground}
            onPress={handleProgressBarTouch}
            disabled={isLoading || !!error}
          >
            <View
              style={[
                styles.progressBar,
                { width: `${isSeeking ? seekPercentage : progressPercentage}%` },
              ]}
            />
          </TouchableOpacity>

          {!isLoading && !error && (
            <View
              {...panResponder.panHandlers}
              style={[
                styles.progressHandle,
                {
                  left: `${isSeeking ? seekPercentage : progressPercentage}%`,
                },
              ]}
            />
          )}
        </View>

        {/* 控制按钮 */}
        <View style={styles.controls}>
          {isLoading ? (
            <ActivityIndicator size="small" color={theme.colors.primary.main} />
          ) : (
            <TouchableOpacity
              style={[
                styles.playButton,
                error && styles.disabledButton
              ]}
              onPress={isPlaying ? handlePause : handlePlay}
              disabled={!!error}
            >
              <Text style={styles.playButtonText}>
                {isPlaying ? '暂停' : '播放'}
              </Text>
            </TouchableOpacity>
          )}
        </View>
      </View>

      {/* 错误信息 */}
      {error && (
        <Text style={styles.errorText}>
          加载失败: {error.message}
        </Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: '100%',
    marginVertical: theme.spacing.md,
  },
  playerContainer: {
    backgroundColor: theme.colors.background.paper,
    borderRadius: theme.borderRadius.md,
    padding: theme.spacing.md,
    ...Platform.select({
      ios: {
        shadowColor: theme.colors.common.black,
        shadowOffset: { width: 0, height: 1 },
        shadowOpacity: 0.1,
        shadowRadius: 2,
      },
      android: {
        elevation: 2,
      },
      web: {
        boxShadow: theme.shadows.sm,
      },
    }),
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: theme.spacing.sm,
  },
  title: {
    flex: 1,
    fontSize: theme.typography.fontSize.md,
    color: theme.colors.text.primary,
    fontWeight: '500',
    marginRight: theme.spacing.sm,
  },
  timeText: {
    fontSize: theme.typography.fontSize.xs,
    color: theme.colors.text.secondary,
  },
  progressContainer: {
    position: 'relative',
    height: 24, // Increased touch target
    justifyContent: 'center',
  },
  progressBackground: {
    height: 6, // Slightly thicker for mobile
    backgroundColor: theme.colors.gray[200],
    borderRadius: 3,
    overflow: 'hidden',
  },
  progressBar: {
    height: '100%',
    backgroundColor: theme.colors.primary.main,
  },
  progressHandle: {
    position: 'absolute',
    width: 16, // Larger for better touch target
    height: 16, // Larger for better touch target
    borderRadius: 8,
    backgroundColor: theme.colors.primary.main,
    top: 4,
    marginLeft: -8,
    ...Platform.select({
      ios: {
        shadowColor: theme.colors.common.black,
        shadowOffset: { width: 0, height: 1 },
        shadowOpacity: 0.2,
        shadowRadius: 1,
      },
      android: {
        elevation: 2,
      },
      web: {
        boxShadow: theme.shadows.xs,
      },
    }),
  },
  controls: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: theme.spacing.md,
  },
  playButton: {
    backgroundColor: theme.colors.primary.main,
    paddingVertical: theme.spacing.sm, // Larger padding for mobile
    paddingHorizontal: theme.spacing.lg,
    borderRadius: theme.borderRadius.md,
    minWidth: 80, // Ensure button has sufficient touch area
  },
  disabledButton: {
    backgroundColor: theme.colors.gray[400],
  },
  playButtonText: {
    color: theme.colors.common.white,
    fontSize: theme.typography.fontSize.md,
    fontWeight: '500',
    textAlign: 'center',
  },
  errorText: {
    marginTop: theme.spacing.sm,
    color: theme.colors.error.main,
    fontSize: theme.typography.fontSize.sm,
    textAlign: 'center',
  },
  rateButton: {
    backgroundColor: theme.colors.gray[200],
    borderRadius: theme.borderRadius.sm,
    paddingHorizontal: theme.spacing.xs,
    paddingVertical: 2,
    marginRight: theme.spacing.sm,
  },
  rateButtonText: {
    fontSize: theme.typography.fontSize.xs,
    color: theme.colors.text.secondary,
    fontWeight: '500',
  },
});

export default AudioPlayer;